<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GSAP动画示例</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
    <style>
    @import url("https://fonts.googleapis.com/css2?family=Tilt+Warp&display=swap");

:root {
	--color-blue: #154084;
	--color-red: #9d2719;
	--color-yellow: #d7b418;
	--color-white: #fff3e7;
	--color-black: #222222;

	--box-size: 200px;

	font-family: "Tilt Warp", sans-serif;
	color: var(--color-text);
	background-color: var(--color-black);
}

body {
	height: 100vh;
	width: 100vw;
	margin: 0;
	padding: 0;
	display: flex;
	justify-content: center;
	align-items: center;
	overflow: hidden;
}

#print_container {
	padding: 12px;
	background-color: var(--color-white);
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 12px;
}

.title_container {
	display: flex;
	justify-content: space-between;
	align-items: end;
}

.title {
	font-size: 5rem;
	line-height: 5rem;
	font-weight: 600;
	letter-spacing: -2px;
	color: var(--color-black);
	margin: 0;
}

.color_pallet {
	display: flex;
}

.color_pallet div {
	width: 20px;
	height: 20px;
}
.color_pallet .blue {
	background-color: var(--color-blue);
}

.color_pallet .red {
	background-color: var(--color-red);
}

.color_pallet .yellow {
	background-color: var(--color-yellow);
}

.color_pallet .black {
	background-color: var(--color-black);
}

#grid_container {
	position: relative;
	width: calc(var(--box-size) * 4);
	height: calc(var(--box-size) * 4);
}

.cell {
	position: absolute;
	pointer-events: none;
	/* border: 1px solid #ffffff82; */
}

.box {
	opacity: 0;
	position: absolute;
	top: 0;
	left: 0;
	width: var(--box-size);
	height: var(--box-size);
	line-height: var(--box-size);
	cursor: pointer;
	overflow: hidden;
}

.box-content {
	height: 100%;
	background-color: rgb(255, 255, 255);
}

    </style>
</head>
<body>
    <div id="print_container">
        <div id="grid_container">
            <!-- Following Eye -->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <defs>
                            <clipPath id="clip-mask">
                                <path fill="none" d="M95.86 50S75.33 79.47 50 79.47 4.14 50 4.14 50 24.67 20.53 50 20.53 95.86 50 95.86 50Z" />
                            </clipPath>
                        </defs>
                        <path fill="var(--color-blue)" d="M0 0h100v100H0z" />
                        <g class="eye">
                            <path fill="var(--color-white)" d="M95.86 50S75.33 79.47 50 79.47 4.14 50 4.14 50 24.67 20.53 50 20.53 95.86 50 95.86 50Z" />
                            <g clip-path="url(#clip-mask)">
                                <circle class="eye-pupil" cx="50" cy="50" r="20.91" fill="var(--color-black)" />
                            </g>
                        </g>
                    </svg>
                </div>
            </div>
            <!-- ROTATING STARS -->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <path fill="var(--color-blue)" d="M0 0h100v100H0z" />
                        <path class="star" d="M42.74 25.48c-10.29 0-18.64-8.34-18.64-18.64 0 10.29-8.34 18.64-18.64 18.64 10.29 0 18.64 8.34 18.64 18.64 0-10.29 8.34-18.64 18.64-18.64Z" fill="var(--color-white)" />
                        <path class="star" d="M94.54 25.48c-10.29 0-18.64-8.34-18.64-18.64 0 10.29-8.34 18.64-18.64 18.64 10.29 0 18.64 8.34 18.64 18.64 0-10.29 8.34-18.64 18.64-18.64Z" fill="var(--color-white)" />
                        <path class="star" d="M42.74 74.52c-10.29 0-18.64-8.34-18.64-18.64 0 10.29-8.34 18.64-18.64 18.64 10.29 0 18.64 8.34 18.64 18.64 0-10.29 8.34-18.64 18.64-18.64Z" fill="var(--color-white)" />
                        <path class="star" d="M94.54 74.52c-10.29 0-18.64-8.34-18.64-18.64 0 10.29-8.34 18.64-18.64 18.64 10.29 0 18.64 8.34 18.64 18.64 0-10.29 8.34-18.64 18.64-18.64Z" fill="var(--color-white)" />
                    </svg>
                </div>
            </div>
            <!-- MORPHING BOXES -->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 200">
                        <defs>
                            <clipPath id="a">
                                <path fill="none" d="M0 0h100v100H0z" />
                            </clipPath>
                        </defs>
                        <path fill="var(--color-blue)" d="M0 0h100v100H0z" />
                        <g clip-path="url(#a)">
                            <g id="circles">
                                <g class="circle">
                                    <circle cx="50" cy="50" r="50" fill="var(--color-white)" />
                                    <path d="M100 50c0 27.61-22.39 50-50 50V0c27.61 0 50 22.39 50 50Z" fill="var(--color-black)" />
                                </g>
                                <g class="circle">
                                    <circle cx="50" cy="250" r="50" fill="var(--color-white)" />
                                    <path d="M100 250c0 27.61-22.39 50-50 50V200c27.61 0 50 22.39 50 50Z" fill="var(--color-black)" />
                                </g>
                                <g class="circle">
                                    <circle cx="50" cy="150" r="50" fill="var(--color-white)" />
                                    <path d="M0 150c0-27.61 22.39-50 50-50v100c-27.61 0-50-22.39-50-50Z" fill="var(--color-black)" />
                                </g>
                            </g>
                        </g>
                    </svg>
                </div>
            </div>
            <!-- HALF CIRCLES -->
            <div class="box">
                <div class="box-content">
                    <svg id="morph-boxes" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <path fill="var(--color-blue)" d="M0 0h100v100H0z" />
                        <path id="morph-box-1" class="morph-box" d="M28.88 8.4H9.87v19.01l19.01 19.01h19.01V27.41L28.88 8.4z" fill="var(--color-black)" />
                        <path id="box-top-1" d="M9.87 8.4h19.01v19.01H9.87z" fill="var(--color-white)" />
                        <path id="morph-box-2" class="morph-box" d="M73.18 8.4H54.17v19.01l19.01 19.01h19.01V27.41L73.18 8.4z" fill="var(--color-black)" />
                        <path id="box-top-2" d="M54.17 8.4h19.01v19.01H54.17z" fill="var(--color-white)" />
                        <path id="morph-box-3" class="morph-box" d="M28.88 53.58H9.87v19.01L28.88 91.6h19.01V72.59L28.88 53.58z" fill="var(--color-black)" />
                        <path id="box-top-3" d="M9.87 53.58h19.01v19.01H9.87z" fill="var(--color-white)" />
                        <path id="morph-box-4" class="morph-box" d="M73.18 53.58H54.17v19.01L73.18 91.6h19.01V72.59L73.18 53.58z" fill="var(--color-black)" />
                        <path id="box-top-4" d="M54.17 53.58h19.01v19.01H54.17z" fill="var(--color-white)" />
                        <g class="morph-shapes">
                            <polygon id="morph-shape-4" points="92.19 72.59 73.18 72.59 73.18 91.6 73.18 91.6 92.19 91.6 92.19 72.59 92.19 72.59" fill="none" />
                            <polygon id="morph-shape-2" points="92.19 27.41 73.18 27.41 73.18 46.42 73.18 46.42 92.19 46.42 92.19 27.41 92.19 27.41" fill="none" />
                            <polygon id="morph-shape-1" points="47.89 27.41 28.88 27.41 28.88 46.42 28.88 46.42 47.89 46.42 47.89 27.41 47.89 27.41" fill="none" />
                            <polygon id="morph-shape-3" points="47.89 72.59 28.88 72.59 28.88 91.6 28.88 91.6 47.89 91.6 47.89 72.59 47.89 72.59" fill="none" />
                        </g>
                    </svg>
                </div>
            </div>
            <!-- FOLLOWING STARS -->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <defs>
                            <clipPath id="half-circle-clip-path">
                                <path fill="none" d="M0 0h100v100H0z" />
                            </clipPath>
                        </defs>
                        <path fill="var(--color-yellow)" d="M0 0h100v100H0z" />
                        <g clip-path="url(#half-circle-clip-path)">
                            <g id="half-circles">
                                <path id="half-circle-1" class="half-circle" d="M0 50C0 22.39 22.39 0 50 0v100C22.39 100 0 77.61 0 50Z" fill="var(--color-blue)" />
                                <path id="half-circle-2" class="half-circle" d="M50 50c0-27.61 22.39-50 50-50v100c-27.61 0-50-22.39-50-50Z" fill="var(--color-blue)" />
                                <path id="half-circle-3" class="half-circle" d="M100 50c0-27.61 22.39-50 50-50v100c-27.61 0-50-22.39-50-50Z" fill="var(--color-blue)" />
                                <path id="half-circle-4" class="half-circle" d="M150 50c0-27.61 22.39-50 50-50v100c-27.61 0-50-22.39-50-50Z" fill="var(--color-blue)" />
                            </g>
                        </g>
                    </svg>
                </div>
            </div>
            <!-- MORPHING HEART -->
            <div class="box">
                <div class="box-content">
                    <svg id="following-stars" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <path fill="var(--color-red)" d="M0 0h100v100H0z" />
                        <path class="rotating-star" fill="var(--color-white)" d="M100 50C72.39 50 50 27.61 50 0c0 27.61-22.39 50-50 50 27.61 0 50 22.39 50 50 0-27.61 22.39-50 50-50Z" />
                        <path class="following-star" fill="var(--color-yellow)" d="M100 50C72.39 50 50 27.61 50 0c0 27.61-22.39 50-50 50 27.61 0 50 22.39 50 50 0-27.61 22.39-50 50-50Z" />
                        <path class="following-star" fill="var(--color-yellow)" d="M100 50C72.39 50 50 27.61 50 0c0 27.61-22.39 50-50 50 27.61 0 50 22.39 50 50 0-27.61 22.39-50 50-50Z" />
                        <path class="following-star" fill="var(--color-yellow)" d="M100 50C72.39 50 50 27.61 50 0c0 27.61-22.39 50-50 50 27.61 0 50 22.39 50 50 0-27.61 22.39-50 50-50Z" />
                        <path class="following-star" fill="var(--color-yellow)" d="M100 50C72.39 50 50 27.61 50 0c0 27.61-22.39 50-50 50 27.61 0 50 22.39 50 50 0-27.61 22.39-50 50-50Z" />
                    </svg>
                </div>
            </div>
            <!-- DRAW SVG LINES -->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <path fill="var(--color-red)" d="M0 0h100v100H0z" />
                        <path id="morph-heart" fill="var(--color-white)" d="M50 15.05c-10.76-10.76-28.22-10.76-38.98 0C.25 25.82.25 43.27 11.02 54.04L50 93.02l38.98-38.98c10.76-10.76 10.76-28.22 0-38.98C78.22 4.3 60.76 4.3 50 15.06Z" />
                        <path id="morph-lip" fill="none" d="M89.74 42.61c-7-7.47-15.48-21.85-28.55-21.85-7.61 0-8.85 6.26-11.18 6.26s-3.58-6.26-11.18-6.26c-13.07 0-21.55 14.38-28.55 21.85-2.98 3.18-7.67 6.22-7.67 6.22s3.22 2.02 5.78 4.61c6.88 6.98 21.46 25.41 41.62 25.8 20.16-.39 34.75-18.82 41.62-25.8 2.56-2.6 5.78-4.61 5.78-4.61s-4.69-3.04-7.67-6.22Z" />
                    </svg>
                </div>
            </div>
            <!-- STRIPES -->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <path fill="var(--color-yellow)" d="M0 0h100v100H0z" />
                        <path class="square-stroke" d="M21.25 0v50c0 15.88 12.87 28.75 28.75 28.75S78.75 65.88 78.75 50" fill="none" stroke="var(--color-blue)" stroke-miterlimit="10" stroke-width="10" />
                        <path class="square-stroke-right" d="M21.25 49.92c0-15.88 12.87-28.75 28.75-28.75s28.75 12.87 28.75 28.75V100" fill="none" stroke="var(--color-blue)" stroke-miterlimit="10" stroke-width="10" />
                        <path class="square-stroke" d="M28.88 0v50c0 11.66 9.46 21.12 21.12 21.12S71.12 61.66 71.12 50" fill="none" stroke="var(--color-white)" stroke-miterlimit="10" stroke-width="10" />
                        <path class="square-stroke-right" d="M28.88 49.92c0-11.66 9.46-21.12 21.12-21.12s21.12 9.46 21.12 21.12V100" fill="none" stroke="var(--color-white)" stroke-miterlimit="10" stroke-width="10" />
                        <path class="square-stroke" d="M36.51 0v50c0 7.45 6.04 13.49 13.49 13.49S63.49 57.45 63.49 50" fill="none" stroke="var(--color-red)" stroke-miterlimit="10" stroke-width="10" />
                        <path class="square-stroke-right" d="M36.51 49.92c0-7.45 6.04-13.49 13.49-13.49s13.49 6.04 13.49 13.49V100" fill="none" stroke="var(--color-red)" stroke-miterlimit="10" stroke-width="10" />
                    </svg>
                </div>
            </div>
            <!-- RANDOM CIRCLES -->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <path d="M0 0h100v100H0z" fill="var(--color-yellow)" />
                        <circle class="random-circle" cx="50" cy="50" r="50" fill="var(--color-white)" />
                        <circle class="random-circle" cx="50" cy="50" r="40" fill="var(--color-blue)" />
                        <circle class="random-circle" cx="50" cy="50" r="30" fill="var(--color-red)" />
                    </svg>
                </div>
            </div>
            <!-- STREACH BARS -->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <path fill="var(--color-white)" d="M0 0h100v100H0z" />
                        <g class="bar">
                            <path id="bar-1" d="M71.97 6.27c-6.07 0-10.98 4.92-10.98 10.98v52.27c0 6.07 4.92 10.98 10.98 10.98s10.98-4.92 10.98-10.98V17.25c0-6.07-4.92-10.98-10.98-10.98Z" fill="var(--color-red)" />
                            <circle id="bar-1-circle-1" cx="71.97" cy="17.25" r="10.98" fill="var(--color-blue)" />
                            <circle cx="71.97" cy="69.52" r="10.98" fill="var(--color-yellow)" />
                            <path id="morph-bar-1" d="M71.97 48.56c-6.07 0-10.98 4.92-10.98 10.98v9.98c0 6.07 4.92 10.98 10.98 10.98s10.98-4.92 10.98-10.98v-9.98c0-6.07-4.92-10.98-10.98-10.98Z" fill="none" />
                        </g>
                        <g class="bar">
                            <path id="bar-2" d="M50 22.42c-6.07 0-10.98 4.92-10.98 10.98v52.27c0 6.07 4.92 10.98 10.98 10.98s10.98-4.92 10.98-10.98V33.4c0-6.07-4.92-10.98-10.98-10.98Z" fill="var(--color-blue)" />
                            <circle cx="50" cy="33.41" r="10.98" fill="var(--color-yellow)" />
                            <circle id="bar-2-circle-2" cx="50" cy="85.68" r="10.98" fill="var(--color-black)" />
                            <path id="morph-bar-2" d="M50.06 22.42c-6.07 0-10.98 4.92-10.98 10.98v9.98c0 6.07 4.92 10.98 10.98 10.98s10.98-4.92 10.98-10.98V33.4c0-6.07-4.92-10.98-10.98-10.98Z" fill="none" />
                        </g>
                        <g class="bar">
                            <path id="bar-3" d="M28.15 7.27c-6.07 0-10.98 4.92-10.98 10.98v52.27c0 6.07 4.92 10.98 10.98 10.98s10.98-4.92 10.98-10.98V18.26c0-6.07-4.92-10.98-10.98-10.98Z" fill="var(--color-red)" />
    
                            <circle id="bar-3-circle-1" cx="28.15" cy="18.26" r="10.98" fill="var(--color-black)" />
                            <circle cx="28.15" cy="70.53" r="10.98" fill="var(--color-blue)" />
                            <path id="morph-bar-3" fill="none" d="M27.86 37.18c-6.06.09-10.81 5.31-10.81 11.38v22.01c0 6.07 4.74 11.28 10.81 11.38 6.15.1 11.16-4.86 11.16-10.98v-22.8c0-6.12-5.01-11.08-11.16-10.98Z" />
                        </g>
                    </svg>
                </div>
            </div>
            <!-- ROTATING DISK-->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <path fill="var(--color-white)" d="M0 0h100v100H0z" />
                        <g id="disk">
                            <path fill="none" d="M0 0h100v100H0z" />
                            <path fill="var(--color-blue)" d="M100 50c0 27.61-22.39 50-50 50S0 77.61 0 50h100Z" />
                        </g>
                        <circle cx="50" cy="50" r="25" fill="var(--color-black)" />
                    </svg>
                </div>
            </div>
            <!-- ARROWS -->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 200">
                        <defs>
                            <clipPath id="a">
                                <path fill="none" d="M0 0h100v100H0z" />
                            </clipPath>
                        </defs>
                        <path fill="var(--color-white)" d="M0 0h100v100H0z" />
                        <g clip-path="url(#a)">
                            <path id="arrow-1" d="M50 0 0 50h100L50 0z" fill="var(--color-red)" />
                            <path id="arrow-2" d="M50 50 0 100h100L50 50z" fill="var(--color-black)" />
                            <path id="arrow-3" d="M50 100 0 150h100l-50-50z" fill="var(--color-red)" />
                            <path id="arrow-4" d="M50 150 0 200h100l-50-50z" fill="var(--color-black)" />
                        </g>
                    </svg>
                </div>
            </div>
            <!-- LINE DRAWING -->
            <div class="box">
                <div class="box-content">
                    <svg id="lines" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <rect fill="var(--color-white)" width="100" height="100" />
                        <path class="line" fill="none" stroke="var(--color-blue)" stroke-miterlimit="10" stroke-width="1" stroke-linecap="round" d="M50 9.95v80.32" />
                    </svg>
                </div>
            </div>
            <!-- STACK ELIPSES -->
            <div class="box">
                <div class="box-content">
                    <svg id="ellipse" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <path fill="var(--color-yellow)" d="M0 0h100v100H0z" />
                        <ellipse class="ellipse" cx="50" cy="25" fill="var(--color-white)" rx="50" ry="25" />
                    </svg>
                </div>
            </div>
            <!-- BALLANCING BALLS -->
            <div class="box">
                <div class="box-content">
                    <svg id="balancing-balls" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <defs>
                            <clipPath id="ball-mask">
                                <path fill="none" d="M0 0h100v100H0z" />
                            </clipPath>
                        </defs>
                        <path fill="var(--color-red)" d="M0 0h100v100H0z" />
                        <g clip-path="url(#ball-mask)">
                            <circle class="ball" id="balance-ball-1" cx="50" cy="87" r="13" fill="var(--color-white)" />
                            <circle class="ball" id="balance-ball-2" cx="50" cy="54" r="19" fill="var(--color-black)" />
                            <circle class="ball" id="balance-ball-3" cx="50" cy="0" r="35" fill="var(--color-yellow)" />
                        </g>
                    </svg>
                </div>
            </div>
            <!-- Following Eye -->
            <div class="box">
                <div class="box-content">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                        <defs>
                            <clipPath id="clip-mask">
                                <path fill="none" d="M95.86 50S75.33 79.47 50 79.47 4.14 50 4.14 50 24.67 20.53 50 20.53 95.86 50 95.86 50Z" />
                            </clipPath>
                        </defs>
                        <path fill="var(--color-red)" d="M0 0h100v100H0z" />
                        <g class="eye">
                            <path fill="var(--color-white)" d="M95.86 50S75.33 79.47 50 79.47 4.14 50 4.14 50 24.67 20.53 50 20.53 95.86 50 95.86 50Z" />
                            <g clip-path="url(#clip-mask)">
                                <circle class="eye-pupil" cx="50" cy="50" r="20.91" fill="var(--color-black)" />
                            </g>
                        </g>
                    </svg>
                </div>
            </div>
        </div>
        <div>
            <div class="title_container">
                <!-- SPLIT TEXT -->
                <p class="title">GSAP GRID</p>
                <div class="color_pallet">
                    <div class="blue"></div>
                    <div class="red"></div>
                    <div class="yellow"></div>
                    <div class="black"></div>
                </div>
            </div>
        </div>
    </div>

    <script>
// Drag and Move mouse around
// Hope you like it :)
// @shunyadezian

console.clear();

gsap.registerPlugin(
	DrawSVGPlugin,
	SplitText,
	Draggable,
	InertiaPlugin
);

const container = document.getElementById("grid_container");

// REVEAL GRID ITEM
const boxes = gsap.utils.toArray(".box");
gsap.to(boxes, {
	autoAlpha: 1,
	duration: 0.8,
	stagger: 0.1,
	ease: "power1.inOut"
});

// Following Eye
// ref: https://gsap.com/community/forums/topic/17962-cursor-follows-the-eyes/
container.addEventListener("mousemove", (e) => {
	const { clientX, clientY } = e;
	const maxTrans = 20;
	const maxX = container.clientWidth / 2;
	const maxY = container.clientHeight / 2;

	const eye = document.querySelectorAll(".eye");
	const pupil = document.querySelectorAll(".eye-pupil");

	for (let i = 0; i < eye.length; i++) {
		const eyeRect = eye[i].getBoundingClientRect();
		const r = eyeRect.width / 2;
		const centerX = eyeRect.left + r;
		const centerY = eyeRect.top + r;

		const x = clientX - centerX;
		const y = clientY - centerY;

		const xPercent = x / maxX;
		const yPercent = y / maxY;

		const scaledXPercent = xPercent * maxTrans;
		const scaledYPercent = yPercent * maxTrans;

		gsap.to(pupil[i], {
			xPercent: scaledXPercent,
			yPercent: scaledYPercent,
			duration: 0.2,
			overwrite: "auto"
		});

		gsap.to(eye[i], {
			xPercent: scaledXPercent * 0.4,
			yPercent: scaledYPercent * 0.4,
			duration: 0.2,
			overwrite: "auto"
		});
	}
});

// ROTATING STARS
const starTL = gsap.timeline({ repeat: -1, repeatDelay: 0.5 });

starTL
	.to(".star", {
		rotate: 360,
		transformOrigin: "50% 50%",
		duration: 1,
		stagger: 0.5
	})
	.to(".star", {
		scale: 1.5,
		transformOrigin: "50% 50%",
		duration: 0.2,
		ease: "power1.out",
		repeat: 1,
		yoyo: true
	});

// ROTATING CIRCLES
gsap.to("#circles", {
	y: -200,
	duration: 1.5,
	ease: "none",
	repeat: -1
});

gsap.to(".circle", {
	rotate: 360,
	transformOrigin: "50% 50%",
	duration: 3,
	repeat: -1,
	ease: "none"
});

// MORPHING BOXES

const morphBoxes = gsap.utils.toArray(".morph-box");
const morphDuration = 1;
morphBoxes.forEach((box, i) => {
	gsap.to(box, {
		morphSVG: `#morph-shape-${i + 1}`,
		duration: morphDuration,
		ease: "power1.inOut",
		repeat: -1,
		yoyo: true,
		delay: i * 0.1
	});

	gsap.to(`#box-top-${i + 1}`, {
		y: 19,
		x: 19,
		duration: morphDuration,
		ease: "power1.inOut",
		repeat: -1,
		yoyo: true,
		delay: i * 0.1
	});
});

// HALF CIRCLES
const halfCircleTl = gsap.timeline({ repeat: -1 }).timeScale(0.5);
const halfCircleEase = "power2.inOut";
const halfCirclesScale = {
	scale: 0,
	transformOrigin: "0% 50%",
	ease: halfCircleEase
};
halfCircleTl
	.to("#half-circle-1", {
		...halfCirclesScale
	})
	.to(
		"#half-circle-2",
		{
			x: -50,
			ease: halfCircleEase
		},
		"<"
	)
	.to(
		"#half-circle-3",
		{
			x: -50,
			transformOrigin: "0% 50%",
			ease: halfCircleEase
		},
		"<"
	)
	.to(
		"#half-circle-4",
		{
			x: -50,
			ease: halfCircleEase
		},
		"<"
	)
	.to("#half-circle-2", {
		...halfCirclesScale
	})
	.to(
		"#half-circle-3",
		{
			x: -100,
			ease: halfCircleEase
		},
		"<"
	)
	.to(
		"#half-circle-4",
		{
			x: -100,
			ease: halfCircleEase
		},
		"<"
	);

// FOLLOWING STARS
// ref: https://gsap.com/community/forums/topic/30502-mouse-cursor-follow-animation/
const starContainer = document.querySelector("#following-stars");

gsap.set(".following-star", {
	xPercent: -50,
	yPercent: -50,
	x: 0,
	y: 100,
	transformOrigin: "center",
	scale: 0
});

let initialMouseMove = true;
let timer;

starContainer.addEventListener("mousemove", (e) => {
	const { clientX, clientY } = e;

	const containerRect = starContainer.getBoundingClientRect();
	const centerX = containerRect.left;
	const centerY = containerRect.top;

	const x = clientX - centerX;
	const y = clientY - centerY;

	// if it's the first mouse movement run this
	if (initialMouseMove) {
		initialMouseMove = false;

		gsap.to(".following-star", {
			scale: 0.4,
			stagger: 0.02,
			ease: "sine.out"
		});
	}

	const mouseStopped = () => {
		// reset this variable
		// so we can track the first mouse move again
		initialMouseMove = true;

		gsap.to(".following-star", {
			scale: 0,
			stagger: 0.02,
			ease: "sine.inOut"
		});
	};

	// // clear the timer every time the mouse moves
	clearTimeout(timer);
	// // set a timer for 0.2 second
	timer = setTimeout(mouseStopped, 20);
	gsap.to(".following-star", {
		duration: 0.5,
		overwrite: "auto",
		x: x / 2,
		y: y / 2,
		stagger: 0.1,
		ease: "none"
	});
});

// MORPHING HEART
gsap.to("#morph-heart", {
	morphSVG: `#morph-lip`,
	duration: 2,
	ease: "power3.inOut",
	repeat: -1,
	yoyo: true
});

// 移除或注释掉以下代码块
// STREACH BARS
gsap.to("#bar-1", {
	morphSVG: "#morph-bar-1",
	duration: 1,
	ease: "power3.inOut",
	repeat: -1,
	yoyo: true
});

gsap.to("#bar-2", {
	morphSVG: "#morph-bar-2",
	duration: 3,
	ease: "sine.inOut",
	repeat: -1,
	yoyo: true
});

gsap.to("#bar-3", {
	morphSVG: "#morph-bar-3",
	duration: 2,
	ease: "circ",
	repeat: -1,
	yoyo: true
});
// RANDOM CIRCLES
const randomCircleTl = gsap.timeline({ repeat: -1, repeatRefresh: true });

randomCircleTl
	.to(".random-circle", {
		x: () => gsap.utils.random(-40, 40, 5),
		y: () => gsap.utils.random(-40, 40, 5),
		scale: 0,
		transformOrigin: "center"
	})
	.to(".random-circle", {
		scale: () => gsap.utils.random(0.7, 1, 0.1),
		duration: 1,
		ease: "power3.inOut",
		stagger: 0.2
	});

// STREACH BARS
gsap.to(".bar", {
	y: -5,
	duration: 1,
	ease: "power1.inOut",
	repeat: -1,
	yoyo: true,
	stagger: 1
});

gsap.to("#bar-1", {
	morphSVG: "#morph-bar-1",
	duration: 1,
	ease: "power3.inOut",
	repeat: -1,
	yoyo: true
});

gsap.to("#bar-1-circle-1", {
	y: 40,
	duration: 1,
	ease: "power3.inOut",
	repeat: -1,
	yoyo: true
});

gsap.to("#bar-2", {
	morphSVG: "#morph-bar-2",
	duration: 3,
	ease: "sine.inOut",
	repeat: -1,
	yoyo: true
});

gsap.to("#bar-2-circle-2", {
	y: -40,
	duration: 3,
	ease: "sine.inOut",
	repeat: -1,
	yoyo: true
});

gsap.to("#bar-3", {
	morphSVG: "#morph-bar-3",
	duration: 2,
	ease: "circ",
	repeat: -1,
	yoyo: true
});

gsap.to("#bar-3-circle-1", {
	y: 30,
	duration: 2,
	ease: "circ",
	repeat: -1,
	yoyo: true
});

// ROTATING DISK
gsap.to("#disk", {
	rotate: 360,
	transformOrigin: "50% 50%",
	duration: 3,
	ease: "elastic.out(1,0.5)",
	repeat: -1,
	yoyo: true
});

// ARROWS
const arrowTL = gsap.timeline({ repeat: -1 });
arrowTL
	.to("#arrow-1", {
		scale: 0,
		transformOrigin: "top center",
		duration: 1,
		ease: "power3.inOut"
	})
	.to(
		"#arrow-2",
		{
			y: -50,
			duration: 1,
			ease: "power3.inOut"
		},
		"<"
	)
	.to("#arrow-3", {
		y: -50,
		duration: 1,
		ease: "power3.inOut"
	})
	.to("#arrow-2", {
		scale: 0,
		transformOrigin: "top center",
		duration: 1,
		ease: "power3.inOut"
	})
	.to(
		"#arrow-3",
		{
			y: -100,
			duration: 1,
			ease: "power3.inOut"
		},
		"<"
	)
	.to("#arrow-4", {
		y: -100,
		duration: 1,
		ease: "power3.inOut"
	});

// LINE DRAWING
const line = document.querySelector("#lines");
const lineOrigin = document.querySelector("#lines path");

// Number of duplicates
const numOfLines = 20;

for (let i = 0; i < numOfLines; i++) {
	const clonedPath = lineOrigin.cloneNode(true);
	clonedPath.setAttribute("class", "line");
	line.appendChild(clonedPath);
}

const lines = gsap.utils.toArray(".line");

lines.forEach((line, i) => {
	gsap.set(line, {
		drawSVG: "100% 0%",
		rotate: (i * 180) / numOfLines,
		transformOrigin: "center"
	});
});

gsap.to(lines, {
	rotate: "+=360",
	ease: "power3.inOut",
	repeat: -1,
	stagger: 0.1,
	duration: 4
});

gsap.to("#lines path", {
	drawSVG: "100% 50%",
	duration: 2,
	ease: "power3.inOut",
	repeat: -1,
	yoyo: true,
	stagger: 0.1
});

// STACK ELIPSES
const ellipse = document.querySelector("#ellipse");
const ellipsOrigin = document.querySelector("#ellipse ellipse");

// Number of duplicates
const numOfEllipses = 10;

for (let i = 0; i < numOfEllipses; i++) {
	const clonedPath = ellipsOrigin.cloneNode(true);
	ellipse.appendChild(clonedPath);
}

const ellipses = gsap.utils.toArray(".ellipse");

ellipses.forEach((ellipse, i) => {
	gsap.set(ellipse, {
		transformOrigin: "bottom center"
	});
});

gsap.to(ellipses, {
	y: 50,
	fill: "#9d2719",
	ease: "power3.inOut",
	stagger: 0.1,
	repeat: -1,
	duration: 1,
	yoyo: true
});

// BALLANCING BALLS
const ballContainer = document.querySelector("#balancing-balls");

gsap.set("#balance-ball-1", {
	xPercent: -190,
	transformOrigin: "center",
	x: 50
});
gsap.set("#balance-ball-2", {
	xPercent: -130,
	transformOrigin: "center",
	x: 50
});
gsap.set("#balance-ball-3", {
	xPercent: -70,
	transformOrigin: "center",
	x: 50
});

ballContainer.addEventListener("mousemove", (e) => {
	const { clientX } = e;

	const containerRect = ballContainer.getBoundingClientRect();
	const centerX = containerRect.left;

	const x = clientX - centerX;

	gsap.to("#balance-ball-1", {
		duration: 0.5,
		overwrite: "auto",
		x: x / 2,
		ease: "power4.out"
	});
	gsap.to("#balance-ball-2", {
		duration: 0.5,
		overwrite: "auto",
		x: x / 2,
		ease: "power4.out",
		delay: 0.02
	});
	gsap.to("#balance-ball-3", {
		duration: 0.5,
		overwrite: "auto",
		x: x / 2,
		ease: "power4.out",
		delay: 0.045
	});
});

ballContainer.addEventListener("mouseleave", () => {
	gsap.to(".ball", {
		x: 50,
		stagger: 0.05,
		ease: "sine.inOut"
	});
});

// SPLIT TEXT
const title = document.querySelector(".title");
const split = new SplitText(title, { type: "chars" });
gsap.from(split.chars, {
	duration: 0.5,
	y: 100,
	stagger: 0.1,
	ease: "back.out"
});

const titleSpinTL = gsap.timeline({ paused: true });
titleSpinTL.to(split.chars, {
	duration: 0.5,
	rotateY: 360,
	stagger: 0.1,
	repeat: 1,
	yoyo: true
});

title.addEventListener("mouseenter", () => {
	titleSpinTL.restart();
});

////////////////////////////////////
// GRID SYSTEM
////////////////////////////////////

//ref: https://codepen.io/osublake/pen/NrRJwm?editors=0110
//ref: https://codepen.io/GreenSock/pen/JjwZzNG?editors=0010

const colSize = 200;
const rowSize = 200;
const gridRows = 4;
const gridColumns = 4;

function createGrid(gridRows, gridColumns) {
	for (let i = 0; i < gridRows * gridColumns; i++) {
		const y = Math.floor(i / gridColumns) * rowSize;
		const x = (i * colSize) % (gridColumns * colSize);

		const cell = document.createElement("div");
		cell.classList.add("cell");
		cell.style.width = colSize - 1 + "px";
		cell.style.height = rowSize - 1 + "px";
		cell.style.top = y + "px";
		cell.style.left = x + "px";
		container.appendChild(cell);
	}
}

createGrid(gridRows, gridColumns);

let clampCol = gsap.utils.clamp(0, gridColumns - 1);
let clampRow = gsap.utils.clamp(0, gridRows - 1);

let cells = [];

// Map cell locations to array
for (let row = 0; row < gridRows; row++) {
	for (let col = 0; col < gridColumns; col++) {
		cells.push({
			row: row,
			col: col,
			x: col * colSize,
			y: row * rowSize
		});
	}
}

let listItems = gsap.utils.toArray(".box").sort(() => 0.5 - Math.random()); // Randomize list items
let sortables = listItems.map(Sortable); // Array of sortables

gsap.to(container, { autoAlpha: 1, duration: 0.5 });

function changeIndex(item, to, sameRow, sameCol) {
	// Check if adjacent to new position
	if ((sameRow && !sameCol) || (!sameRow && sameCol)) {
		// Swap positions in array
		var temp = sortables[to];
		sortables[to] = item;
		sortables[item.index] = temp;
	} else {
		// Change position in array
		arrayMove(sortables, item.index, to);
	}

	// Simple, but not optimized way to change element's position in DOM. Not always necessary.
	sortables.forEach((sortable) => container.appendChild(sortable.element));

	// Set index for each sortable
	sortables.forEach((sortable, index) => sortable.setIndex(index));
}

function Sortable(element, index) {
	let content = element.querySelector(".box-content");

	let animation = gsap.to(content, {
		duration: 0.3,
		boxShadow: "rgba(0,0,0,0.8) 0px 16px 32px 0px",
		force3D: true,
		scale: 1.1,
		paused: true
	});

	let dragger = new Draggable(element, {
		onDragStart: downAction,
		onRelease: upAction,
		onDrag: dragAction
	});

	// let position = element._gsTransform;
	let getProp = gsap.getProperty(element);

	// Public properties and methods
	let sortable = {
		cell: cells[index],
		dragger: dragger,
		element: element,
		index: index,
		setIndex: setIndex
	};

	gsap.set(element, {
		x: sortable.cell.x,
		y: sortable.cell.y
	});

	function setIndex(index) {
		let cell = cells[index];
		// var dirty = position.x !== cell.x || position.y !== cell.y;
		let dirty = getProp("x") !== cell.x || getProp("y") !== cell.y;

		sortable.cell = cell;
		sortable.index = index;

		// Don't layout if you're dragging
		if (!dragger.isDragging && dirty) layout();
	}

	function downAction() {
		animation.play();
		this.update();
	}

	function dragAction() {
		let col = clampCol(Math.round(this.x / colSize));
		let row = clampRow(Math.round(this.y / rowSize));

		let cell = sortable.cell;
		let sameCol = col === cell.col;
		let sameRow = row === cell.row;

		// Check if position has changed
		if (!sameRow || !sameCol) {
			// Calculate the new index
			var index = gridColumns * row + col;

			// Update the model
			changeIndex(sortable, index, sameRow, sameCol);
		}
	}

	function upAction() {
		animation.reverse();
		layout();
	}

	function layout() {
		gsap.to(element, {
			duration: 0.3,
			x: sortable.cell.x,
			y: sortable.cell.y
		});
	}

	return sortable;
}

// Changes an elements's position in array
function arrayMove(array, from, to) {
	array.splice(to, 0, array.splice(from, 1)[0]);
}
    </script>
</body>
</html>
